﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using NAnt.Core;
using System.Xml;
using CodeMadeSimple.Common.Tests;
using System.IO;
using EnvRide.Core.UnitTests;
using CodeMadeSimple.PropertiesManagement;
using CodeMadeSimple.PropertiesManagement.Tests;
using CodeMadeSimple.PropertiesManagement.NAnt.Tasks;

namespace EnvRide.NAnt.Tests
{
    [TestFixture]
    public class EnvRideTaskTests : EnvRideBaseTest
    {
        private static readonly string ENV_1_NAME = "Env1";
        private static readonly string ENV_1_OUTPUT_FILE = "Env1.xml";
        private static readonly string ENV_2_NAME = "Env2";
        private static readonly string ENV_2_OUTPUT_FILE = "Env2.xml";

        [Test]
        public void Execute()
        { 
            XmlDocument doc = new XmlDocument();
            doc.LoadXml("<project></project>");

            Project proj = new Project(doc, Level.Error, 0);

            EnvRideTask task = new EnvRideTask();
            task.Project = proj;

            task.FilePath = null;

            ExceptionAssert.AssertNullReferenceException("FilePath", () => task.Execute());

            task.FilePath = "";

            ExceptionAssert.AssertEmptyStringException("FilePath", () => task.Execute());

            task.FilePath = "NonExistentFile";

            Assert.Throws<FileNotFoundException>(() => task.Execute(), "The file \"NonExistentFile\" was not found!");

            task.FilePath = "EnvRideTask.envRide";

            Appender.Clear();

            task.Execute();

            AssertHasNoErrors(task.Arguments);

            AssertFile.Exists(ENV_1_OUTPUT_FILE);
            AssertFile.Exists(ENV_2_OUTPUT_FILE);

            XmlDocument output1 = new XmlDocument();
            output1.Load(ENV_1_OUTPUT_FILE);

            Assert.AreEqual("attValue1", output1.DocumentElement.GetAttribute("att"));

            XmlDocument output2 = new XmlDocument();
            output2.Load(ENV_2_OUTPUT_FILE);

            Assert.AreEqual("attValue2", output2.DocumentElement.GetAttribute("att"));

            task.Environment = ENV_1_NAME;

            DeleteGeneratedFiles();

            Appender.Clear();

            task.Execute();

            AssertFile.Exists(ENV_1_OUTPUT_FILE);
            AssertFile.DoesNotExist(ENV_2_OUTPUT_FILE);

            output1 = new XmlDocument();
            output1.Load(ENV_1_OUTPUT_FILE);

            Assert.AreEqual("attValue1", output1.DocumentElement.GetAttribute("att"));

            task.Environment = ENV_2_NAME;

            DeleteGeneratedFiles();

            Appender.Clear();

            task.Execute();

            AssertHasNoErrors(task.Arguments);

            AssertFile.DoesNotExist(ENV_1_OUTPUT_FILE);
            AssertFile.Exists(ENV_2_OUTPUT_FILE);

            output1 = new XmlDocument();
            output1.Load(ENV_2_OUTPUT_FILE);

            Assert.AreEqual("attValue2", output1.DocumentElement.GetAttribute("att"));

            task.FilePath = "EnvRideTaskWithProps.envRide";

            DeleteGeneratedFiles();

            Appender.Clear();

            task.Environment = null;

            task.Execute();

            AssertHasErrors(task.Arguments, new[] { GetPropertyContainerNullMessage(), GetPropertyContainerNullMessage() });

            AssertFile.Exists(ENV_1_OUTPUT_FILE);
            AssertFile.Exists(ENV_2_OUTPUT_FILE);

            output1.Load(ENV_1_OUTPUT_FILE);

            Assert.AreEqual("${Prop}", output1.DocumentElement.GetAttribute("att"));

            output2.Load(ENV_2_OUTPUT_FILE);

            Assert.AreEqual("${Prop}", output2.DocumentElement.GetAttribute("att"));

            task.PropContainer = "Ctx";

            Appender.Clear();

            Assert.Throws<ArgumentException>(() => task.Execute(), PropertyContextManagerTests.GetContextNotFoundMessage(task.PropContainer));

            PropertyContext propCtx = new PropertyContext("Ctx");
            propCtx.AddProperty(new CodeMadeSimple.PropertiesManagement.Property { Name = "Prop", Value = "ValueInCtx" });

            NAntPropertyContextManager.Instance.AddContext(propCtx);

            Appender.Clear();

            task.Execute();

            AssertHasNoErrors(task.Arguments);

            AssertFile.Exists(ENV_1_OUTPUT_FILE);
            AssertFile.Exists(ENV_2_OUTPUT_FILE);

            output1.Load(ENV_1_OUTPUT_FILE);

            Assert.AreEqual("ValueInCtx", output1.DocumentElement.GetAttribute("att"));

            output2.Load(ENV_2_OUTPUT_FILE);

            Assert.AreEqual("ValueInCtx", output2.DocumentElement.GetAttribute("att"));

            task.PropContainerType = PropertyContainerType.Stack;

            DeleteGeneratedFiles();

            Appender.Clear();

            Assert.Throws<ArgumentException>(() => task.Execute(), PropertyContextManagerTests.GetStackNotFoundMessage(task.PropContainer));

            task.PropContainer = "Stack";

            DeleteGeneratedFiles();

            Appender.Clear();

            Assert.Throws<ArgumentException>(() => task.Execute(), PropertyContextManagerTests.GetStackNotFoundMessage(task.PropContainer));

            PropertyContextStack stack = new PropertyContextStack("Stack");

            stack.AddContext(propCtx);

            NAntPropertyContextManager.Instance.AddStack(stack);

            DeleteGeneratedFiles();

            Appender.Clear();

            task.Execute();

            AssertHasNoErrors(task.Arguments);

            AssertFile.Exists(ENV_1_OUTPUT_FILE);
            AssertFile.Exists(ENV_2_OUTPUT_FILE);

            output1.Load(ENV_1_OUTPUT_FILE);

            Assert.AreEqual("ValueInCtx", output1.DocumentElement.GetAttribute("att"));

            output2.Load(ENV_2_OUTPUT_FILE);

            Assert.AreEqual("ValueInCtx", output2.DocumentElement.GetAttribute("att"));

            PropertyContext propCtx2 = new PropertyContext("Ctx2");
            propCtx2.AddProperty(new CodeMadeSimple.PropertiesManagement.Property { Name = "Prop", Value = "ValueInStack" });

            stack.AddContext(propCtx2);

            DeleteGeneratedFiles();

            Appender.Clear();

            task.Execute();

            AssertHasNoErrors(task.Arguments);

            AssertFile.Exists(ENV_1_OUTPUT_FILE);
            AssertFile.Exists(ENV_2_OUTPUT_FILE);

            output1.Load(ENV_1_OUTPUT_FILE);

            Assert.AreEqual("ValueInStack", output1.DocumentElement.GetAttribute("att"));

            output2.Load(ENV_2_OUTPUT_FILE);

            Assert.AreEqual("ValueInStack", output2.DocumentElement.GetAttribute("att"));

            task.Environment = ENV_1_NAME;

            DeleteGeneratedFiles();

            Appender.Clear();

            task.Execute();

            AssertHasNoErrors(task.Arguments);

            AssertFile.Exists(ENV_1_OUTPUT_FILE);
            AssertFile.DoesNotExist(ENV_2_OUTPUT_FILE);

            output1.Load(ENV_1_OUTPUT_FILE);

            Assert.AreEqual("ValueInStack", output1.DocumentElement.GetAttribute("att"));
        }

        public override void TearDown()
        {
            base.TearDown();

            DeleteGeneratedFiles();
        }

        private static void DeleteGeneratedFiles()
        {
            File.Delete(ENV_1_OUTPUT_FILE);
            File.Delete(ENV_2_OUTPUT_FILE);
        }
    }
}
